package Thread;
/**死锁情况一：对同一个锁对象多次加锁，Java的解决办法：可重入锁*/

class Counter1 {
    private int count = 0;
    public void add() {
        synchronized (this) {
            count++;
        }
    }

    public int get() {
        return count;
    }

}
/*synchronized对于同一个锁对象counter多次加锁，第一次加锁时，可以成功；
但是第二次加锁，锁对象已经被占用，第二次的加锁会触发阻塞等待，要想解除阻塞等待，就要向下执行，
想要向下执行，必须释放锁，这就引发了死锁的问题，为了解决上述问题，synchronized引入了
可重入的概念，当某个线程针对一个锁，加锁成功后对这个线程再次针对这个锁进行加锁，不会触发阻塞等待，
但是如果其他的线程尝试加锁，就会触发阻塞等待。针对一个线程，一把锁连续多次加锁的情况*/

public class demo19 {
    public static void main(String[] args) throws InterruptedException {

        Counter1 counter = new Counter1();

        Thread t1 = new Thread(()->{
            for (int i = 0; i < 5000; i++) {
                synchronized (counter) {
                    synchronized (counter) {
                        synchronized (counter) {
                            counter.add();
                        }
                    }
                }
            }
        });
        t1.start();
        t1.join();
        System.out.println("count = " + counter.get());
    }
}

/*可重入锁的概念
在 Java 中，synchronized 是一种可重入锁。可重入锁（Reentrant Lock）是指同一个线程可以多次获取
同一个锁而不会导致死锁。具体来说，如果一个线程已经持有了某个锁，那么它可以在不释放该锁的情况下再次获取该锁，
而不会被自己阻塞。*/
// 假设没有可重入锁，那么在一个线程已经持有一个锁的情况下，如果它再次尝试获取同一个锁，将会被自己阻塞，从而导致死锁

/*synchronized 关键字实现了可重入锁的特性。具体来说：

1.锁的计数器：每个 synchronized 锁都有一个计数器，记录当前锁被持有的次数。
2.首次加锁：当一个线程首次获取到锁时，计数器设为1。
3.多次加锁：如果同一个线程再次获取同一个锁，计数器会递增。
4.解锁：当线程释放锁时，计数器递减。只有当计数器为0时，锁才会真正被释放，其他线程才能获取该锁。*/